import os
from PIL import Image
import logging
from typing import List, Tuple
from datetime import datetime
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton, 
                           QLabel, QFileDialog, QRadioButton, QButtonGroup,
                           QSpinBox, QCheckBox, QListWidget, QListWidgetItem,
                           QScrollArea, QGroupBox, QGridLayout, QComboBox, QTextEdit)
from PyQt6.QtCore import Qt, QSize, QThread, pyqtSignal
from PyQt6.QtGui import QPixmap, QImage, QIcon
import time

class ProcessWorker(QThread):
    """处理图片的工作线程"""
    progress_signal = pyqtSignal(str)  # 进度信号
    finished_signal = pyqtSignal(str)  # 完成信号
    error_signal = pyqtSignal(str)     # 错误信号

    def __init__(self, processor, img_path, save_dir, split_num):
        super().__init__()
        self.processor = processor
        self.img_path = img_path
        self.save_dir = save_dir
        self.split_num = split_num

    def run(self):
        try:
            self.processor.split_image(self.img_path, self.save_dir, self.split_num)
            self.finished_signal.emit(f"完成处理: {os.path.basename(self.img_path)}")
        except Exception as e:
            self.error_signal.emit(f"处理失败 {os.path.basename(self.img_path)}: {str(e)}")

class ProgressMonitor(QThread):
    """监控处理进度的线程"""
    finished_signal = pyqtSignal()  # 完成信号

    def __init__(self, processor):
        super().__init__()
        self.processor = processor

    def run(self):
        while any(worker.isRunning() for worker in self.processor.workers):
            time.sleep(0.1)
        self.finished_signal.emit()

class ImageProcessor(QWidget):
    def __init__(self):
        super().__init__()
        self.images_path: List[str] = []
        # 设置默认输出目录为用户的图片文件夹
        self.output_dir = os.path.join(os.path.expanduser("~"), "Pictures", "ImageSplitter")
        self.init_ui()
        
    def init_ui(self):
        layout = QVBoxLayout(self)
        
        # 定义按钮样式
        style_sheet = """
            QPushButton {
                background-color: #2196F3;
                color: white;
                border: none;
                padding: 5px 15px;
                border-radius: 3px;
            }
            QPushButton:hover {
                background-color: #1976D2;
            }
            QPushButton:pressed {
                background-color: #0D47A1;
            }
            QPushButton:disabled {
                background-color: #BDBDBD;
                color: #757575;
            }
        """
        
        # 文件选择和预览区域
        file_preview_layout = QHBoxLayout()
        
        # 左侧文件列表
        list_layout = QVBoxLayout()
        self.file_list = QListWidget()
        self.file_list.setIconSize(QSize(100, 100))  # 设置图标大小
        self.file_list.itemClicked.connect(self.show_preview)
        list_layout.addWidget(self.file_list)
        
        # 文件操作按钮
        btn_layout = QHBoxLayout()
        select_btn = QPushButton("选择图片")
        select_btn.clicked.connect(self.select_images)
        select_btn.setStyleSheet(style_sheet)  # 应用样式
        
        clear_btn = QPushButton("清除选择")
        clear_btn.clicked.connect(self.clear_selection)
        clear_btn.setStyleSheet(style_sheet)  # 应用样式
        
        delete_btn = QPushButton("删除所选")
        delete_btn.clicked.connect(self.delete_selected)
        delete_btn.setStyleSheet(style_sheet)  # 应用样式
        
        btn_layout.addWidget(select_btn)
        btn_layout.addWidget(delete_btn)
        btn_layout.addWidget(clear_btn)
        list_layout.addLayout(btn_layout)
        
        file_preview_layout.addLayout(list_layout)
        
        # 右侧预览区域
        preview_layout = QVBoxLayout()
        preview_label = QLabel("预览")
        preview_layout.addWidget(preview_label)
        
        # 创建固定大小的预览区域
        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setMinimumWidth(400)
        scroll.setFixedHeight(300)  # 固定高度
        
        self.preview_image = QLabel()
        self.preview_image.setAlignment(Qt.AlignmentFlag.AlignCenter)
        scroll.setWidget(self.preview_image)
        preview_layout.addWidget(scroll)
        
        file_preview_layout.addLayout(preview_layout)
        layout.addLayout(file_preview_layout)
        
        # 分割选项区域
        split_layout = QHBoxLayout()
        split_label = QLabel("分割方式：")
        self.split_group = QButtonGroup()
        nine_split = QRadioButton("九等分")
        four_split = QRadioButton("四等分")
        nine_split.setChecked(True)
        self.split_group.addButton(nine_split, 9)
        self.split_group.addButton(four_split, 4)
        split_layout.addWidget(split_label)
        split_layout.addWidget(nine_split)
        split_layout.addWidget(four_split)
        split_layout.addStretch()
        layout.addLayout(split_layout)
        
        # 在分割选项区域添加新的控制选项
        options_layout = QVBoxLayout()
        
        # 输出设置
        output_group = QGroupBox("输出设置")
        output_layout = QGridLayout()
        
        # 输出格式
        format_label = QLabel("输出格式：")
        self.format_combo = QComboBox()
        self.format_combo.addItems(["PNG", "JPEG", "BMP", "WEBP"])
        output_layout.addWidget(format_label, 0, 0)
        output_layout.addWidget(self.format_combo, 0, 1)
        
        output_group.setLayout(output_layout)
        options_layout.addWidget(output_group)
        
        # 将选项添加到主布局
        layout.addLayout(options_layout)
        
        # 保存选项区域
        save_layout = QHBoxLayout()
        self.separate_folders = QCheckBox("每张图片单独文件夹")
        self.separate_folders.setChecked(True)
        
        output_btn = QPushButton("选择输出目录")
        output_btn.clicked.connect(self.select_output_dir)
        output_btn.setStyleSheet(style_sheet)  # 应用样式
        
        self.output_label = QLabel(f"输出目录：{self.output_dir}")
        
        save_layout.addWidget(self.separate_folders)
        save_layout.addWidget(output_btn)
        save_layout.addWidget(self.output_label)
        save_layout.addStretch()
        layout.addLayout(save_layout)
        
        # 处理按钮
        process_btn = QPushButton("处理图片")
        process_btn.setObjectName("process_btn")
        process_btn.clicked.connect(self.process_images)
        process_btn.setStyleSheet(style_sheet)  # 应用样式
        layout.addWidget(process_btn)
        
        # 创建信息显示的滚动区域
        info_scroll = QScrollArea()
        info_scroll.setWidgetResizable(True)
        info_scroll.setFixedHeight(150)  # 增加高度
        
        info_container = QWidget()
        info_layout = QVBoxLayout(info_container)
        
        # 使用单个 QTextEdit 作为信息显示控件
        self.info_label = QTextEdit()
        self.info_label.setReadOnly(True)
        info_layout.addWidget(self.info_label)
        
        info_scroll.setWidget(info_container)
        layout.addWidget(info_scroll)
        
        # 底部按钮
        bottom_layout = QHBoxLayout()
        
        open_output_btn = QPushButton("打开输出位置")
        open_output_btn.setObjectName("open_output_btn")
        open_output_btn.clicked.connect(lambda: self.open_output_dir(self.output_dir))
        open_output_btn.setStyleSheet(style_sheet)  # 应用样式
        
        bottom_layout.addStretch()
        bottom_layout.addWidget(open_output_btn)
        bottom_layout.addStretch()
        
        layout.addLayout(bottom_layout)
        
        # 最后添加弹性空间
        layout.addStretch()
    
    def select_images(self):
        """选择图片文件"""
        files, _ = QFileDialog.getOpenFileNames(
            self,
            "选择图片",
            "",
            "图片文件 (*.png *.jpg *.jpeg *.bmp *.gif);;所有文件 (*.*)"
        )
        if files:
            self.images_path.extend(files)
            self.update_file_list()
            self.show_images_info()
    
    def update_file_list(self):
        """更新文件列表显示"""
        self.file_list.clear()
        for path in self.images_path:
            item = QListWidgetItem()
            # 创建缩略图
            pixmap = QPixmap(path)
            pixmap = pixmap.scaled(100, 100, Qt.AspectRatioMode.KeepAspectRatio)
            icon = QIcon(pixmap)
            item.setIcon(icon)
            item.setText(os.path.basename(path))
            item.setData(Qt.ItemDataRole.UserRole, path)  # 存储完整路径
            self.file_list.addItem(item)
    
    def show_preview(self, item):
        """显示选中图片的预览"""
        path = item.data(Qt.ItemDataRole.UserRole)
        pixmap = QPixmap(path)
        # 等比例缩放到预览区域
        scaled_pixmap = pixmap.scaled(
            self.preview_image.width(),
            self.preview_image.height(),
            Qt.AspectRatioMode.KeepAspectRatio
        )
        self.preview_image.setPixmap(scaled_pixmap)
    
    def delete_selected(self):
        """删除选中的图片"""
        items = self.file_list.selectedItems()
        for item in items:
            path = item.data(Qt.ItemDataRole.UserRole)
            self.images_path.remove(path)
            self.file_list.takeItem(self.file_list.row(item))
        self.show_images_info()
        self.preview_image.clear()
    
    def select_output_dir(self):
        """选择输出目录"""
        dir_path = QFileDialog.getExistingDirectory(
            self,
            "选择输出目录",
            self.output_dir  # 使用当前输出目录为起始目录
        )
        if dir_path:
            self.output_dir = dir_path
            self.output_label.setText(f"输出目录：{dir_path}")
    
    def process_images(self):
        """处理图片（多线程版本）"""
        if not self.images_path:
            self.log_message("未选择图片，操作终止")
            return

        try:
            self.log_message(f"开始处理图片，共 {len(self.images_path)} 张")
            
            # 创建输出目录
            output_dir = os.path.join(
                self.output_dir, 
                f"split_images_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
            )
            os.makedirs(output_dir, exist_ok=True)
            self.log_message(f"创建输出目录: {output_dir}")

            split_num = self.split_group.checkedId()
            
            # 创建线程池
            self.workers = []
            self.processed_count = 0  # 添加处理计数器
            self.total_count = len(self.images_path)  # 总数
            
            # 禁用处理按钮和打开输出位置按钮
            process_btn = self.findChild(QPushButton, "process_btn")
            open_output_btn = self.findChild(QPushButton, "open_output_btn")
            if process_btn:
                process_btn.setEnabled(False)
            if open_output_btn:
                open_output_btn.setEnabled(False)
            
            for img_path in self.images_path:
                if self.separate_folders.isChecked():
                    img_name = os.path.splitext(os.path.basename(img_path))[0]
                    save_dir = os.path.join(output_dir, img_name)
                    os.makedirs(save_dir, exist_ok=True)
                else:
                    save_dir = output_dir

                # 创建工作线程
                worker = ProcessWorker(self, img_path, save_dir, split_num)
                worker.progress_signal.connect(self.log_message)
                worker.finished_signal.connect(self.on_worker_finished)
                worker.error_signal.connect(self.log_message)
                self.workers.append(worker)
                worker.start()

            # 创建并启动监控线程
            self.monitor = ProgressMonitor(self)
            self.monitor.finished_signal.connect(self.on_all_completed)
            self.monitor.start()

            # 更新打开输出目录按钮的路径
            if open_output_btn:
                open_output_btn.clicked.disconnect()
                open_output_btn.clicked.connect(lambda: self.open_output_dir(output_dir))

        except Exception as e:
            self.log_message(f"处理失败: {str(e)}")

    def on_worker_finished(self, message: str):
        """单个工作线程完成时的处理"""
        self.processed_count += 1
        progress = (self.processed_count / self.total_count) * 100
        self.log_message(f"{message} - 总进度: {progress:.1f}%")

    def on_all_completed(self):
        """所有工作线程完成时的处理"""
        self.log_message("所有图片处理完成！")
        
        # 重新启用按钮
        process_btn = self.findChild(QPushButton, "process_btn")
        open_output_btn = self.findChild(QPushButton, "open_output_btn")
        if process_btn:
            process_btn.setEnabled(True)
        if open_output_btn:
            open_output_btn.setEnabled(True)

    def save_image(self, img: Image.Image, save_path: str):
        """保存图片"""
        # 获取保存格式
        fmt = self.format_combo.currentText().lower()
        save_path = os.path.splitext(save_path)[0] + f".{fmt}"
        
        # 保存图片
        img.save(save_path)
    
    def split_image(self, image_path: str, save_dir: str, split_num: int):
        """分割图片"""
        try:
            logging.info(f"开始分割图片: {image_path}")
            with Image.open(image_path) as img:
                # 转换为RGB模式
                if img.mode != 'RGB':
                    img = img.convert('RGB')
                
                width, height = img.size
                logging.info(f"图片尺寸: {width}x{height}")
                
                if split_num == 9:
                    logging.info("执行九等分")
                    w_step = width // 3
                    h_step = height // 3
                    for i in range(3):
                        for j in range(3):
                            box = (j * w_step, i * h_step, 
                                  (j + 1) * w_step, (i + 1) * h_step)
                            split = img.crop(box)
                            save_path = os.path.join(
                                save_dir,
                                f"{os.path.splitext(os.path.basename(image_path))[0]}_split_{i*3+j+1}"
                            )
                            self.save_image(split, save_path)
                            logging.info(f"保存分割图片: {save_path}")
                else:
                    logging.info("执行四等分")
                    w_step = width // 2
                    h_step = height // 2
                    for i in range(2):
                        for j in range(2):
                            box = (j * w_step, i * h_step, 
                                  (j + 1) * w_step, (i + 1) * h_step)
                            split = img.crop(box)
                            save_path = os.path.join(
                                save_dir,
                                f"{os.path.splitext(os.path.basename(image_path))[0]}_split_{i*2+j+1}"
                            )
                            self.save_image(split, save_path)
                
            logging.info(f"图片分割完成: {image_path}")
        except Exception as e:
            logging.error(f"分割图片失败: {image_path}", exc_info=True)
            raise
    
    def clear_selection(self):
        """清除选择的图片"""
        self.images_path.clear()
        self.file_list.clear()
        self.info_label.clear()
        self.preview_image.clear()  # 清除预览图片
    
    def show_images_info(self):
        """显示图片信息"""
        try:
            info = []
            for path in self.images_path:
                with Image.open(path) as img:
                    size_mb = os.path.getsize(path) / (1024 * 1024)
                    info.append(f"文件：{os.path.basename(path)}\n"
                              f"尺寸：{img.size[0]}x{img.size[1]}\n"
                              f"大小：{size_mb:.2f}MB\n"
                              f"格式：{img.format}\n")
            self.info_label.clear()  # 清除之前的内容
            self.info_label.setPlainText("\n".join(info))  # 使用 setPlainText 设置文本
        except Exception as e:
            logging.error(f"读取图片信息失败: {str(e)}")
            self.info_label.setPlainText(f"读取图片信息失败: {str(e)}")
    
    def open_output_dir(self, path: str):
        """打开输出目录"""
        import subprocess
        import platform
        
        try:
            if platform.system() == "Windows":
                os.startfile(path)
            elif platform.system() == "Darwin":  # macOS
                subprocess.run(["open", path])
            else:  # linux
                subprocess.run(["xdg-open", path])
        except Exception as e:
            logging.error(f"打开输出目录失败: {str(e)}")
            self.info_label.setText(f"打开输出目录失败: {str(e)}")
    
    def log_message(self, message: str):
        """记录日志消息"""
        timestamp = time.strftime("%H:%M:%S")
        log_msg = f"[{timestamp}] {message}"
        print(log_msg)  # 终端输出
        self.info_label.append(log_msg)  # GUI输出
        self.info_label.verticalScrollBar().setValue(
            self.info_label.verticalScrollBar().maximum()
        )